package com.jilujia.framework.domain;

import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public abstract class AbstractPoEntityManager<ID extends Serializable, PO extends PoEntity<ID>, Repository extends JpaBusinessRepository<ID, PO>> {

	private static final Logger LOG = LoggerFactory.getLogger(AbstractPoEntityManager.class);

	private ID id;

	private PO instance;

	private Repository repository;

	@Autowired
	private ApplicationContext applicationContext;

	@Transactional
	protected void save() {
		Assert.notNull(instance, "Required instance must not be null");
		this.preSave();

		this.setInstance(repository.save(instance));

		this.postSave();
	}

	protected void postSave() {
	}

	protected void preSave() {
	}

	@Transactional
	public void remove() {
		Assert.notNull(instance, "Required instance must not be null");
		Assert.notNull(id, "Required instance's id must not be null");
		this.preRemove();
		repository.delete(instance);
		this.postRemove();

		this.setInstance(null);
	}

	@Transactional
	public void removeById(ID id) {
		Assert.notNull(id, "Required id must not be null");
		findOneById(id);
		if (instance != null) {
			this.remove();
		}
	}

	protected void postRemove() {
	}

	protected void preRemove() {
	}

	@Transactional(readOnly = true)
	public void findOne() {
		Assert.notNull(id, "Required id must not be null");
		findOneById(id);
	}

	@Transactional(readOnly = true)
	public void findOneById(ID id) {
		Assert.notNull(id, "Required id must not be null");
		this.id = id;
		instance = repository.findOne(id);
	}

	@Autowired
	public void setRepository(Repository repository) {
		this.repository = repository;
	}

	public Repository getRepository() {
		return repository;
	}

	public void setId(ID id) {
		this.id = id;
	}

	public ID getId() {
		return id;
	}

	public void setInstance(PO instance) {
		if (instance == null) {
			this.instance = null;
			this.id = null;
		} else {
			this.instance = instance;
			this.id = instance.getId();
		}
	}

	public PO getInstance() {
		return instance;
	}

	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	public ApplicationContext getApplicationContext() {
		return applicationContext;
	}
}
